#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <mutex>
#include <tuple>
#include "base/Bytes.h"
#include <sw/redis++/redis++.h>
// #include "RedisClientInstance.h"
#include "MessageQueue.h"
#include "DelayQueue.h"
#include "DeadLetterQueue.h"
#include <shared_mutex>

namespace zeroplus::mq
{
    class RedisStore
    {
    private:
        std::shared_ptr<DelayQueue> delayQueue_;
        std::shared_ptr<MessageQueue> messageQueue_;
        std::shared_ptr<DeadLetterQueue> deadLetterQueue_;
        std::shared_mutex rwMtx_;
        std::shared_ptr<sw::redis::Redis> redis_;
        static std::shared_ptr<RedisStore> instance_;
        static std::mutex mtx_;

    private:
        RedisStore(const std::string &uri);
        RedisStore(const RedisStore &) = delete;
        RedisStore &operator=(const RedisStore &) = delete;

    public:
        static std::shared_ptr<RedisStore> getInstance(const std::string &uri);

        virtual ~RedisStore();
        // 创建topic队列
        std::string CreateMQ(const std::string &topic);
        // 写入消息队列
        std::string WriteToMQ(const std::string &topic, const Bytes &message);
        // 读取消息队列
        std::tuple<Bytes, std::string, bool> ReadFromMQ(const std::string &topic, const std::string &consumerGroup, const std::string &consumerId,
                                                        const int &count = 1, const int &blockSeconds = 0);
        // 写入延迟队列
        bool WriteToDQ(const std::string &topic, const uint64_t &delay, const Bytes &message);
        // 写入死信队列
        bool WriteToDLQ(const std::string &topic, const uint64_t &delay, const Bytes &message);
        // 获取队列的大小
        long GetQueueSize(const std::string &topic);
        // 检查key是否存在
        bool IsTopicExists(const std::string &topic);
        // 扫描所有key，并返回所有stream类型的key
        std::vector<std::string> GetAllTopic();
        // 消息应答
        bool AckMessage(const std::string &topic, const std::string &messageId, const std::string &groupName);
        // 重新消费
        bool Reconsume(const std::string &topic, const std::string &consumerGroup, const std::string &consumerId, const std::string &messageId);
    };
}
